package com.walterweimod.auxiliary_attributes.util;

import com.google.common.collect.Multimap;
import com.walterweimod.auxiliary_attributes.attribute.ModAttributes;
import net.minecraft.network.protocol.game.ClientboundUpdateAttributesPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LerpingModel;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.*;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;

import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

public class ModAttributeUtils {
    private ModAttributeUtils(){}

    public static AttributeSupplier getDefaultValueAttributeSupplier(Attribute... attributes){
        AttributeSupplier.Builder attributeBuilder = LivingEntity.createLivingAttributes();

        if (ArrayUtils.isNotEmpty(attributes)){
            for (Attribute attribute : attributes) {
                attributeBuilder.add(attribute, attribute.getDefaultValue());
            }
        }

        return attributeBuilder.build();
    }

    public static AttributeSupplier getAttributeSupplier(Map<Attribute, Double> map){
        AttributeSupplier.Builder attributeBuilder = LivingEntity.createLivingAttributes();

        if (Objects.nonNull(map) && !map.isEmpty()){
            map.forEach(attributeBuilder::add);
        }

        return attributeBuilder.build();
    }

    public static void addTransientAttributeModifier(LivingEntity livingEntity,
                                                     Attribute attribute,
                                                     double value,
                                                     String name,
                                                     AttributeModifier.Operation operation){
        addAttributeModifier(
                livingEntity,
                attribute,
                value,
                getNameAttributeUUID(attribute, name),
                operation,
                true
        );
    }

    public static void addAttributeModifier(LivingEntity livingEntity,
                                            Attribute attribute,
                                            double value,
                                            UUID uuid,
                                            AttributeModifier.Operation operation,
                                            boolean isTransient){
        if (Objects.nonNull(livingEntity) && !livingEntity.level.isClientSide()){
            AttributeInstance attributeInstance = livingEntity.getAttribute(attribute);

            if (ObjectUtils.allNotNull(attribute, operation, attributeInstance, uuid)){
                AttributeModifier modifier = new AttributeModifier(uuid, "Add Attribute Modifier", value, operation);
                attributeInstance.removeModifier(uuid);

                if (isTransient){
                    attributeInstance.addTransientModifier(modifier);
                }else {
                    attributeInstance.addPermanentModifier(modifier);
                }

            }
        }
    }

    public static void removeAttributeModifier(LivingEntity livingEntity,
                                               Attribute attribute,
                                               UUID uuid){
        if (Objects.nonNull(livingEntity) && !livingEntity.level.isClientSide()){
            AttributeInstance attributeInstance = livingEntity.getAttribute(attribute);

            if (ObjectUtils.allNotNull(attributeInstance, uuid)){
                attributeInstance.removeModifier(uuid);
                syncAttributesToClient(livingEntity);

                if (Objects.equals(attribute, Attributes.MAX_HEALTH)){
                    syncHealth(livingEntity);
                }
            }
        }
    }

    public static void removeAttributeModifiers(LivingEntity livingEntity,
                                                Multimap<Attribute, UUID> multimap){
        if (Objects.nonNull(multimap)
                && !multimap.isEmpty()
                && !livingEntity.level.isClientSide()){
            multimap.entries().forEach(entry -> removeAttributeModifier(
                    livingEntity, entry.getKey(), entry.getValue()
            ));
        }
    }

    private static void syncAttributesToClient(LivingEntity livingEntity) {
        if (livingEntity instanceof ServerPlayer serverPlayer) {
            serverPlayer.connection.send(
                    new ClientboundUpdateAttributesPacket(
                            livingEntity.getId(),
                            livingEntity.getAttributes().getSyncableAttributes()
                    )
            );
        }
    }

    public static void syncHealth(LivingEntity livingEntity){
        if (Objects.nonNull(livingEntity)){
            float maxHealth = livingEntity.getMaxHealth();

            if (livingEntity.getHealth() > maxHealth){
                livingEntity.setHealth(maxHealth);
            }
        }
    }

    public static UUID getNameAttributeUUID(Attribute attribute, String name){
        UUID uuid = UUID.randomUUID();

        if (Objects.nonNull(attribute)){
            uuid = UUID.nameUUIDFromBytes((attribute.getDescriptionId() + "_" + name).getBytes());
        }

        return uuid;
    }
}
